//
//  SocketUtil.swift
//  TestSocket
//
//  Created by yxl on 2022/8/12.
//

import Foundation
import SocketIO
import SwiftyJSON


// MARK: - 发送消息
enum SocketSendEvent: String {
    // 客户端断开连接
    case disconnect = "disconnect"
    // 退出房间
    case leave_room = "leave_room"
    // 用户信息变更
    case player_info_change = "player_info_change"
    // 发送消息
    case message = "message"
    // 加入房间
    case join_room = "join_room"
    // 用户信息上报
    case user_info_report = "user_info_report"
}

// MARK: - 接收消息
enum SocketReceiveEvent: String {
    // 客户端断开连接
    case disconnect = "disconnect"
    // 查询房间用户
    case get_room_users = "get_room_users"
    // 客户端连接
    case cli_connect = "cli_connect"
    // 聊天消息
    case message = "message"
    // 房间消息
    case room_msg = "room_msg"
    // 客户端连接异常
    case connect_error = ""
    // 客户端socket 消息异常
    case cli_err = "cli_err"
    // 客户端socket 全局消息
    case broad_cast = "broad_cast"
}

// 自定义Log
public func Log<T>(_ message: T, file: String = #file, funcName: String = #function, lineNum: Int = #line) {
#if DEBUG
    let fileName = (file as NSString).lastPathComponent;
    print("🔨 [文件名：\(fileName)], [方法：\(funcName)], [行数：\(lineNum)]\n🔨 \(message)");
#endif
}

/// 默认打印
public func Log<T>(_ message: T) {
#if DEBUG
    print("\(message)")
#endif
}

class SocketUtil {
    let WSURL = URL(string: "http://10.0.41.219:10246")
    static let share = SocketUtil()
    private var manager:SocketManager?
    private var socket:SocketIOClient?
    // [] 里面传递需要的字段 ，比如版本号  [ "h": HttpRequestUtil.share.platformVersion]
    private var socketHeaders : [String:String] = [:]
    private var config:SocketIOClientConfiguration = []
    
    private init() {
        NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
    }
    
    /// 已经进入前台
    @objc func willEnterForeground() {
        
    }
     
    /// 已经进入后台
    @objc private func didEnterBackground() {
        
    }
    
    //  MARK: - Public
    /// 连接socket
    public func connect(authorization:String, uid:String){
        if manager != nil {
            //断开连接
            disconnect()
        }
        config = [
            .log(false),//打印日志
            .compress,
            .connectParams(["source":3, "Authorization":authorization, "uid":uid]),
            .extraHeaders(socketHeaders),
            .reconnects(true), //是否重连机制
            .reconnectWaitMax(100) //重新连接等待最大秒数
        ]
        manager = SocketManager(socketURL: WSURL!, config: config)
        socket = manager?.defaultSocket
        // 监听socket连接状态
        listeningStatus()
        listeningMsgEvent()
        socket?.connect()
    }
    
    /// 断开连接
    public func disconnect() {
        self.manager?.disconnect()
        self.manager = nil
        self.socket = nil
    }
    
    // MARK: - Private
    /// 监听scoket状态变化
    private func listeningStatus() {
        socket?.on(clientEvent: .disconnect) { data, ack in
            guard let status = data.first as? SocketIOStatus else {
                return
            }
            Log("socket status change: \(status)")
            if status == .disconnected {
                let state = UIApplication.shared.applicationState
                if (state != .background) {
//                    if UserUtil.share.isLogin() {
                    //登陆情况下直接重连
                        self.reconnect()
//                    }
                }
            }
        }
        /// 异常
        socket?.on(clientEvent: .error) { data, ack in
            Log("socket error: \(data)")
        }
    }
    
    /// 重新连接
    private func reconnect() {
        guard let socket = socket else {
            return
        }
        guard socket.status != .connected && socket.status != .connecting else {
            return
        }
        manager?.reconnect()
    }
    
    /// 字典转string
    func getJSONStringFromDictionary(dictionary:NSDictionary) -> String {
        if (!JSONSerialization.isValidJSONObject(dictionary)) {
            return ""
        }
        let data : NSData! = try? JSONSerialization.data(withJSONObject: dictionary, options: []) as NSData?
        let JSONString = NSString(data:data as Data,encoding: String.Encoding.utf8.rawValue)
        return JSONString! as String
    }
}

// Mark: - 接收消息
extension SocketUtil {
    /// 监听所有消息事件
    private func listeningMsgEvent() {
        // MARK: - 聊天消息
        socket?.on(SocketReceiveEvent.message.rawValue) { data, ack in
            Log(data)
            // 告知后台已收到消息
//            if !stringIsEmpty(str: ids) {
//                ack.with(ids)
//            }
        }
        
        // MARK: - 房间消息
        socket?.on(SocketReceiveEvent.room_msg.rawValue) { data, ack in
            Log(data)
            // 告知后台已收到消息
//            if !stringIsEmpty(str: ids) {
//                ack.with(ids)
//            }
        }
    }
}

// MARK: - 发送消息
extension SocketUtil {
    // MARK: - 发送消息（公共），发送消息后无需做任何处理可用
    public func messageSend(_ msgEvent: SocketSendEvent, params: [String: Any]? = nil) {
        let paramsStr = self.getJSONStringFromDictionary(dictionary: params! as NSDictionary)
        // 发送socket事件
        socket?.emitWithAck(msgEvent.rawValue, paramsStr).timingOut(after: 5) { data in
            // 请求超时
            if data.first as? String ?? "passed" == SocketAckStatus.noAck.rawValue {
                Log("发送消息超时")
                return
            }
            Log("发送消息成功")
        }
    }
    
    // MARK: - 发送聊天消息
    public func chatMessageSend(_ msgEvent: SocketSendEvent, params: [String: Any]? = nil) {
        let paramsStr = self.getJSONStringFromDictionary(dictionary: params! as NSDictionary)
        // 发送socket事件
        socket?.emitWithAck(msgEvent.rawValue, paramsStr).timingOut(after: 5) { data in
            // 请求超时
            if data.first as? String ?? "passed" == SocketAckStatus.noAck.rawValue {
                Log("发送聊天消息超时")
                return
            }
            Log("发送聊天消息成功")
        }
    }
    
    // MARK: - 发送用户变更消息
    public func playerInfoChangeSend(_ msgEvent: SocketSendEvent, params: [String: Any]? = nil) {
        let paramsStr = self.getJSONStringFromDictionary(dictionary: params! as NSDictionary)
        // 发送socket事件
        socket?.emitWithAck(msgEvent.rawValue, paramsStr).timingOut(after: 5) { data in
            // 请求超时
            if data.first as? String ?? "passed" == SocketAckStatus.noAck.rawValue {
                Log("发送用户变更消息超时")
                return
            }
            Log("发送用户变更消息成功")
        }
    }
}
